//------------------------------------------------------------------------------
// <copyright company="Telligent Systems">
//     Copyright (c) Telligent Systems Corporation.  All rights reserved.
// </copyright> 
//------------------------------------------------------------------------------

using System;
using System.Collections;
using System.Security;
using System.Web.Services;
using System.Web.Services.Protocols;
using CommunityServer.Blogs.Components;
using CommunityServer.Components;

namespace CommunityServer.Blogs.Components
{
	/// <summary>
	/// BlogService provides a web service interface for posting and editing posts and articles
	/// </summary>
	[ WebService(Name="BlogService",Description="Community Server :: Blogs Posting Web Service",Namespace="http://communityserver.org/blogs/services/posts/")]
	public class BlogService : CSWebServiceBase
	{
		public BlogService()
		{
		}

		#region BlogPost

		public struct BlogPost
		{
			public int PostID;

			public string Title;
			public string Body;
			public string FormattedBody;
			public DateTime Date;
			public string Excerpt;
			public string Name;
			public string Custom;
			public string[] Categories;

			public bool IsPublished;
			public bool EnableComments;
			public bool EnableTrackbacks;
			public bool EnableRatings;
			public bool Syndicate;
			public bool SyndicateExcerpt;
			public bool SydicateRoot;
			public bool IsArticle;

			public CommentModerationType ModerationType;

			public bool EnableAllOwnerNotification;
			public FeedbackNotificationType FeedbackNotificationType;
			public bool EnableCrossPosting;
		}

		#endregion

		#region Service Methods

		[WebMethod(MessageName="Blogs",Description="Returns a list of blog the current user has post access to",EnableSession=false)]
		[SoapHeader("Credentials")]
		public string[] Blogs()
		{
			Login();

			ArrayList blogs = Weblogs.GetWeblogs(true,false,false);
			blogs = Sections.FilterByAccessControl(blogs,Permission.Post,CurrentUser);
			string[] blogList = new string[blogs.Count];
			for(int i = 0; i<blogs.Count; i++)
				blogList[i] = ((Weblog)blogs[i]).ApplicationKey;

			return blogList;

		}

		[WebMethod(MessageName="Create",Description="Creates a new Post",EnableSession=false)]
		[SoapHeader("Credentials")]
		public int Create(BlogPost post)
		{
			LoginSetSection();
			WeblogPost wp = CreatePost(post);

            int postID = -1;
            BlogPostResults result = WeblogPosts.Add(wp,CurrentUser, out postID);
            
            ProcessPostResults(result);
			
            return postID;
		}

		[WebMethod(MessageName="Update",Description="Updates an existing post",EnableSession=false)]
		[SoapHeader("Credentials")]
		public void Update(BlogPost post)
		{
			LoginSetSection();
			WeblogPost wp = CreatePost(post);
			BlogPostResults result = WeblogPosts.Update(wp,CurrentUser.UserID);
            ProcessPostResults(result);
		}

		[WebMethod(MessageName="Delete",Description="Deletes a post by the PostID",EnableSession=false)]
		[SoapHeader("Credentials")]
		public void Delete(int PostID)
		{
			LoginSetSection();
			WeblogPost post = WeblogPosts.GetPost(PostID,false,false,false);
			if(post == null)
				throw new ArgumentOutOfRangeException("Post does not exist");

			if(post.SectionID == CurrentWeblog.SectionID)
			{
				WeblogPosts.Delete(post,CurrentUser.UserID);
				return;
			}
			throw new SecurityException("PostID does not match current Weblog");
		}

		[WebMethod(MessageName="GetRecentPosts",Description="Returns an array of recent posts",EnableSession=false)]
		[SoapHeader("Credentials")]
		public BlogPost[] GetRecentPosts(int count)
		{
			LoginSetSection();
			return CreatePostArray(count,false);
		}

		[WebMethod(MessageName="GetRecentArticles",Description="Returns an array of recent articles",EnableSession=false)]
		[SoapHeader("Credentials")]
		public BlogPost[] GetRecentArticles(int count)
		{
			LoginSetSection();
			return CreatePostArray(count,true);
		}


		[WebMethod(MessageName="GetPostCategories",Description="Returns a list of Category Names",EnableSession=false)]
		[SoapHeader("Credentials")]
		public string[] GetPostCategories()
		{
			LoginSetSection();

			ArrayList al = PostCategories.GetCategories(CurrentWeblog.SectionID,false,true);
			string[] sa = new string[al.Count];
			for(int i = 0; i<al.Count; i++)
			{
				sa[i] = ((PostCategory)al[i]).Name;
			}

			return sa;
		}

		#endregion

		#region Internal Members and Helper Methods

		protected Weblog CurrentWeblog = null;
		

		#region Create Post

        private void ProcessPostResults(BlogPostResults result)
        {
            if(result == BlogPostResults.Success)
                return;

            if(result == BlogPostResults.DuplicationName)
                throw new Exception(ResourceManager.GetString("Weblog_Exception_DuplicatePostName"));

            if(result == BlogPostResults.DuplicateBody)
                throw new Exception(ResourceManager.GetString("Weblog_Exception_DuplicatePostBody"));
        }

		private WeblogPost CreatePost(BlogPost post)
		{
			if(Globals.IsNullorEmpty(post.Title) || Globals.IsNullorEmpty(post.Body))
				throw new ArgumentException("Post Title and Body must not be Null or Empty");

			bool isNew = post.PostID == 0;

			WeblogPost wp = null;
			if(isNew)
			{
				wp = new WeblogPost();
				wp.BlogPostType = post.IsArticle ? BlogPostType.Article : BlogPostType.Post;
				wp.PostType = PostContentType.HTML;
				wp.SectionID = CurrentWeblog.SectionID;
			}

			else
			{
				wp = WeblogPosts.GetPost(post.PostID,false, false,false);
				if(wp == null)
					throw new ArgumentException("Post does not exist");

				if(wp.SectionID != CurrentWeblog.SectionID)
					throw new SecurityException("PostID does not match current Weblog");
			}


			wp.Subject = post.Title;
			wp.Body = post.Body;
			wp.FormattedBody = post.FormattedBody;
			wp.Custom = post.Custom;
			wp.Categories = post.Categories;
			wp.EnableRatings = post.EnableRatings;
			wp.EnableTrackBacks = post.EnableTrackbacks;
			wp.Excerpt = post.Excerpt;
			wp.IsAggregated = post.Syndicate;
			wp.IsApproved = post.IsPublished;
			wp.IsCommunityAggregated = post.SydicateRoot;
            wp.IsLocked = !post.EnableComments;
			wp.ModerationType = post.ModerationType;
			wp.Name = post.Name;
            
			wp.UserTime = UserTime.ConvertToUserTime(post.Date);
            wp.PostDate = post.Date;
            
			wp.SyndicateExcerpt = post.SyndicateExcerpt;
			wp.Username = CurrentUser.Username;

			wp.EnableAllOwnerNotification = post.EnableAllOwnerNotification;
			wp.FeedbackNotificationType = post.FeedbackNotificationType;
			wp.EnableCrossPosting = post.EnableCrossPosting;
	
			return wp;
		}
		#endregion

		protected override void AllocateSection()
		{
			if(Globals.IsNullorEmpty(Credentials.SectionName))
				throw new SecurityException("Invalid (or unsupplied) Blogname");

			CurrentWeblog = Weblogs.GetWeblog(Credentials.SectionName.ToLower(),true);

			if(CurrentWeblog == null)
				throw new ArgumentException(string.Format("The Weblog {0} does not exist"), Credentials.SectionName);

			Permissions.AccessCheck(CurrentWeblog,Permission.Post,CurrentUser);

		}

		private BlogPost ConvertWeblogPostToBlogPost(WeblogPost post)
		{
			BlogPost bp = new  BlogPost();

			bp.Title = post.Subject;
			bp.Body = post.Body;
			bp.FormattedBody = post.FormattedBody;
			bp.Custom = post.Custom;
			bp.Categories = post.Categories;
			bp.EnableComments = !post.IsLocked;
			bp.EnableRatings = post.EnableRatings;
			bp.EnableTrackbacks = post.EnableTrackBacks;
			bp.Excerpt = post.Excerpt;
			bp.Syndicate = post.IsAggregated;
			bp.IsPublished = post.IsApproved;
			bp.SydicateRoot = post.IsCommunityAggregated;
			bp.ModerationType = post.ModerationType;
			bp.EnableAllOwnerNotification = post.EnableAllOwnerNotification;
			bp.FeedbackNotificationType = post.FeedbackNotificationType;
			bp.EnableCrossPosting = post.EnableCrossPosting;
			bp.Name = post.Name;
            //ASMX fiddles with dates for timezones, so we should send back the local server time
			bp.Date = post.PostDate; 
			bp.SyndicateExcerpt = post.SyndicateExcerpt;
			bp.PostID = post.PostID;

			return bp;
		}

		private BlogPost[] CreatePostArray(int count, bool isArticle)
		{
			WeblogConfiguration config = WeblogConfiguration.Instance();
			if(count > config.ServicePostCountLimit) count = config.ServicePostCountLimit;

			BlogThreadQuery query = BlogThreadQuery.CreateNewSingleBlogQuery(CurrentWeblog.SectionID);
			query.PublishedFilter = BlogPostPublishedFilter.All;
			query.PageIndex = 0;
			query.PageSize = count;
			query.BlogPostType = isArticle ? BlogPostType.Article : BlogPostType.Post;

			ThreadSet threads = WeblogPosts.GetBlogThreads(query,false);

			BlogPost[] posts = new BlogPost[threads.Threads.Count];
			for(int i  =0; i<threads.Threads.Count; i++)
			{
				WeblogPost post = threads.Threads[i] as WeblogPost;
				posts[i] = ConvertWeblogPostToBlogPost(post);
			}

			return posts;
		}

		#endregion


	}
}
